// Wrapper of fetch
// https://github.github.io/fetch/
// fetch(url, {
//   method: "POST",
//   body: JSON.stringify(data),
//   headers: {
//     "Content-Type": "application/json"
//   },
//   credentials: "same-origin"
// }).then(function(response) {
//   response.status     //=> number 100–599
//   response.statusText //=> String
//   response.headers    //=> Headers
//   response.url        //=> String
//
//   return response.text()
// }, function(error) {
//   error.message //=> String
// })

const queryString = require('query-string');

const objectAssignDeep = require('object-assign-deep');

const parseJSON = (response) => {
  let contentType = response.headers.get('content-type'),
    isOk = response.ok,
    output = '';

  if (contentType && contentType.indexOf('application/json') !== -1) {
    output = response.json();
  } else {
    output = response.text();
  }

  if (isOk) {
    return output;
  }
  return output.then((res) => {
    if (typeof res === 'string') {
      throw new Error(res);
    } else {
      throw res.errorCode;
    }
  });
};

function handleErrors(response) {
  if (!response.ok) {
    throw Error(response.statusText);
  }
  return response;
}

const Hfetch = {
  defaultHeader: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  get(url, payload, options) {
    return fetch(`${url}?${queryString.stringify(payload)}`, objectAssignDeep({}, {
      method: 'GET',
      headers: this.defaultHeader,
    }, options))
      .then(parseJSON, parseJSON);
  },
  post(url, payload, options) {
    return fetch(url, objectAssignDeep({}, {
      method: 'POST',
      headers: this.defaultHeader,
      body: JSON.stringify(payload),
    }, options))
      .then(parseJSON, parseJSON);
  },
  put(url, payload, options) {
    return fetch(url, objectAssignDeep({}, {
      method: 'PUT',
      headers: this.defaultHeader,
      body: JSON.stringify(payload),
    }, options)).then(handleErrors);
  },
  del(url, options) {
    return fetch(url, objectAssignDeep({}, {
      method: 'DELETE',
      headers: this.defaultHeader,
    }, options)).then(handleErrors);
  },
  patch(url, payload, options) {
    return fetch(url, objectAssignDeep({}, {
      method: 'PATCH',
      headers: this.defaultHeader,
      body: JSON.stringify(payload),
    }, options)).then(handleErrors);
  },
};

module.exports = Hfetch;
